home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / misc / sci / RARS_Amiga_3.lha / RARS / blender.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-27  |  16.2 KB  |  525 lines

  1. //Date: Fri, 12 May 1995 13:17:33 -0500
  2. //From: cburke@mitre.org (Carl D. Burke)
  3. //Subject: blender -- driver entry for 4mile race
  4.  
  5. /* Blender (blender(); blender.cpp)
  6.    Carl Burke (cburke@mitre.org)
  7.  
  8.    This is a dynamic (reentrant) driver program for RARS.  It's my third
  9.    and so far most successful attempt.  The first two tries were neural
  10.    networks of various types, with learning supplied by a genetic algorithm.
  11.    Neither did particularly well, although the second try got fairly decent
  12.    speeds (and lots of damage).  This program uses some concepts derived
  13.    from developing the neural net drivers and some code from the TUT3 'bot;
  14.    it's generally faster and takes less damage, but isn't yet in the same
  15.    class as WappuCar, Indretti, or the latest Ramdu in short races.  It does
  16.    have some minimal passing behavior, but no memory; it tends to wiggle
  17.    a lot in extended passing sequences on straightaways.  Cars behind it
  18.    are ignored; I leave it up to THEM to pass ME.
  19.  
  20.    The parameters were originally seeded with the TUT3 values, then allowed
  21.    to drift with a genetic algorithm (single crossover, a small percentage
  22.    of weights receiving +-5% mutations in each generation; 400 individuals
  23.    in each generation, evaluated with 50 races of 8 drivers on each of
  24.    7 tracks; selecting for (1) pole position, (2) average speed, and (3)
  25.    amount of damage at the end of the race).  Since it takes a considerable
  26.    amount of time to run a generation (currently 50 minutes on an SGI Indigo 2),
  27.    only 50 generations were run before packaging the best set of parameters
  28.    for the 4mile.trk endurance race.
  29.  
  30.    This 'bot has been tested with the Unix/X port of v0.5.  It successfully
  31.    completed 50 laps of fourmile.trk, beating the other two survivors (Rudy
  32.    and the 0.39 Ramdu2) by 2 and 3 laps, respectively.
  33.    I haven't tested this code on the PC, with or without the Borland compiler;
  34.    I'm using the SGI ANSI C compiler, which should be compatible, but I don't
  35.    know the code/data size.
  36. */
  37.  
  38. #include <string.h>
  39. #include <stdlib.h>
  40. #include <math.h>
  41. #include "car.h"
  42. #include <stdio.h>
  43.  
  44. #define NUM_RAD_CATS  32
  45. #define MAX_RAD_CAT (NUM_RAD_CATS-1)
  46. #define LEFT_TOO_CLOSE 0.1
  47. #define RIGHT_TOO_CLOSE 0.9
  48. #define VEL_INTERVAL 6
  49.  
  50.     float STEER_GAIN[] = {
  51.       -0.48,-0.48,-0.52,-0.47,-0.50,-0.53,-0.50,-0.50,
  52.       -0.50,-0.49,-0.54,-0.50,-0.52,-0.50,-0.47,-0.51,
  53.       -0.51,-0.51,-0.50,-0.50,-0.54,-0.50,-0.49,-0.52,
  54.       -0.46,-0.48,-0.52,-0.48,-0.46,-0.49,-0.49,-0.50
  55.       };
  56.     float DAMP_GAIN[] = {
  57.        2.00, 1.98, 2.05, 2.14, 1.92, 2.00, 2.07, 2.03,
  58.        2.00, 1.86, 2.10, 2.09, 2.00, 2.04, 2.18, 1.92,
  59.        2.05, 1.98, 1.96, 1.82, 1.95, 2.08, 2.03, 1.89,
  60.        1.98, 2.08, 1.98, 2.07, 1.98, 2.00, 2.01, 1.95
  61.       };
  62.     float VC[] = {
  63.       212.36, 9.38,15.76,26.20,42.40,85.23,130.42,203.04,
  64.       303.36,495.97,829.75,1400.22,2532.72,3857.52,5701.30,9898.29,
  65.       303.36,303.36,303.36,303.36,303.36,303.36,303.36,303.36,
  66.       303.36,303.36,303.36,303.36,303.36,303.36,303.36,303.36
  67.       };
  68.     float BIAS[] = {
  69.       0,0.0124815,0.00337826,0.000833944,0.000193107,
  70.       4.50358e-05,1.04967e-05,2.29944e-06,4.99283e-07,
  71.       1.18413e-07,2.54341e-08,5.77603e-09,1.30733e-09,
  72.       2.84956e-10,6.50293e-11,1.33113e-11,3.12386e-12,
  73.       7.20806e-13,1.55528e-13,3.45403e-14,7.89733e-15,
  74.       1.84584e-15,3.85515e-16,9.14617e-17,2.00144e-17,
  75.       4.34022e-18,9.77549e-19,2.20388e-19,4.98952e-20,
  76.       1.06157e-20,2.91439e-21,5.58335e-22
  77.       };
  78.     float LANE_RATIO[] = {
  79.        0.19, 0.18, 0.22, 0.20, 0.20, 0.20, 0.20, 0.20,
  80.        0.20, 0.21, 0.21, 0.20, 0.21, 0.19, 0.22, 0.21,
  81.        0.20, 0.20, 0.20, 0.20, 0.21, 0.20, 0.20, 0.21,
  82.        0.20, 0.18, 0.21, 0.20, 0.21, 0.20, 0.19, 0.19
  83.       };
  84.     float DIST_PARM[] = {
  85.        0.29, 0.24, 0.24, 0.25, 0.26, 0.25, 0.25, 0.25,
  86.        0.25, 0.25, 0.25, 0.27, 0.25, 0.25, 0.24, 0.28,
  87.        0.26, 0.25, 0.27, 0.26, 0.26, 0.24, 0.27, 0.24,
  88.        0.24, 0.26, 0.28, 0.25, 0.25, 0.28, 0.24, 0.25
  89.       };
  90.  
  91. con_vec Blender(situation& s)
  92. {
  93.    const char name[] = "Blender";    // This is the robot driver's name!
  94.    static int init_flag = 1;          // cleared by first call
  95.    con_vec result;                    // This is what is returned.
  96.    double alpha, vc;                  // components of result
  97.    double width;
  98.  
  99.    double lft_ratio, rgt_ratio;
  100.    double vc_cur, vc_nex;
  101.    double alpha_cur, alpha_nex, damp_gain, bias;
  102.    double dist_parm;
  103.    int collrisk_x[3], collrisk_y[3], coll_cnt;
  104.    int i;
  105.    float dval, dist_val, coll_vc, coll_alpha, colltime, pred_rely, pred_relx;
  106.    float dist_val_after, vc_after;
  107.    float turn_size;
  108.  
  109.    float v_int = s.v/VEL_INTERVAL;
  110.    int lowv = (int)v_int;
  111.    int highv = lowv+1;
  112.    float lowv_wt = highv - v_int;
  113.    float highv_wt = v_int - lowv;
  114.  
  115.    if (lowv < 0) lowv = 0;
  116.    if (highv < 0) highv = 0;
  117.    if (lowv > MAX_RAD_CAT) lowv = MAX_RAD_CAT;
  118.    if (highv > MAX_RAD_CAT) highv = MAX_RAD_CAT;
  119.    dist_parm = (lowv_wt*DIST_PARM[lowv] + highv_wt*DIST_PARM[highv]);
  120.  
  121.    if(init_flag == 1)  {  // first time only, copy name:
  122.       my_name_is(name);
  123.       init_flag = 0;
  124.       result.alpha = result.vc = 0;
  125.       return result;
  126.    }
  127.  
  128.    // service routine in the host software to handle getting unstuck from
  129.    // from crashes and pileups:
  130.    if(stuck(s.backward, s.v,s.vn, s.to_lft,s.to_rgt, &result.alpha,&result.vc))
  131.       return result;
  132.  
  133.    width = s.to_lft + s.to_rgt;   // compute width of track
  134.    lft_ratio = s.to_lft/width;
  135.    rgt_ratio = s.to_rgt/width;
  136.    // calculate alpha for current turn
  137.    {
  138.       float lane_ratio, steer_gain;
  139.        if (s.cur_rad == 0.0)
  140.        {
  141.  
  142.       // lane control for straightaway should be minimal; just keep it in
  143.       // the road (check for "too close" to edge and steer away)
  144.  
  145.       lane_ratio = 0.0;
  146.       if (lft_ratio < LEFT_TOO_CLOSE)
  147.       {
  148.           lane_ratio = LEFT_TOO_CLOSE - lft_ratio;
  149.       }
  150.       else if (lft_ratio > RIGHT_TOO_CLOSE)
  151.       {
  152.           lane_ratio = rgt_ratio - RIGHT_TOO_CLOSE;
  153.       }
  154.       steer_gain = STEER_GAIN[0];
  155.       damp_gain = DAMP_GAIN[0];
  156.       bias = 0.0;
  157.       vc_cur = VC[0];
  158.       dist_val = s.to_end;
  159.        }
  160.        else if (s.cur_rad > 0.0)
  161.        {
  162.       float ln_rad = log(s.cur_rad + s.to_lft);
  163.       int low = 1 + (int)ln_rad;
  164.       int high = low+1;
  165.       float low_wt = high - ln_rad;
  166.       float high_wt = ln_rad - low;
  167.  
  168.       if (low < 1) low = 1;
  169.       if (high < 1) high = 1;
  170.       if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
  171.       if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
  172.       lane_ratio = (low_wt*LANE_RATIO[low] + high_wt*LANE_RATIO[high])
  173. - lft_ratio;
  174.       steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
  175.       damp_gain = (low_wt*DAMP_GAIN[low] + high_wt*DAMP_GAIN[high]);
  176.       bias = (low_wt*BIAS[low] + high_wt*BIAS[high]);
  177.       vc_cur = (low_wt*VC[low] + high_wt*VC[high]);
  178.       dist_val = s.to_end * s.cur_rad;
  179.        }
  180.        else if (s.cur_rad < 0.0)
  181.        {
  182.       float ln_rad;
  183.       int low;
  184.       int high;
  185.       float low_wt;
  186.       float high_wt;
  187.       float radius_temp;
  188.  
  189.       radius_temp = -(s.cur_rad + s.to_rgt);
  190.       ln_rad = log(-s.cur_rad + s.to_rgt);
  191.       low = 1 + (int)ln_rad;
  192.       high = low+1;
  193.       low_wt = high - ln_rad;
  194.       high_wt = ln_rad - low;
  195.       if (low < 1) low = 1;
  196.       if (high < 1) high = 1;
  197.       if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
  198.       if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
  199.       lane_ratio = rgt_ratio - (low_wt*LANE_RATIO[low] +
  200. high_wt*LANE_RATIO[high]);
  201.       steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
  202.       damp_gain = (low_wt*DAMP_GAIN[low] + high_wt*DAMP_GAIN[high]);
  203.       bias = -(low_wt*BIAS[low] + high_wt*BIAS[high]);
  204.       vc_cur = (low_wt*VC[low] + high_wt*VC[high]);
  205.       dist_val = -s.to_end * s.cur_rad;
  206.        }
  207.        alpha_cur = steer_gain * lane_ratio;
  208.    }
  209.  
  210.    // calculate alpha for following turn
  211.    {
  212.       float lane_ratio, steer_gain;
  213.        if (s.nex_rad == 0.0)
  214.        {
  215.       // should try to use lane_ratio for following turn if close enough
  216.       // lane control for straightaway should be minimal; just keep it in
  217.       // the road (check for "too close" to edge and steer away)
  218.  
  219.       lane_ratio = 0.0;
  220.       if (lft_ratio < LEFT_TOO_CLOSE)
  221.       {
  222.           lane_ratio = LEFT_TOO_CLOSE - lft_ratio;
  223.       }
  224.       else if (lft_ratio > RIGHT_TOO_CLOSE)
  225.       {
  226.           lane_ratio = rgt_ratio - RIGHT_TOO_CLOSE;
  227.       }
  228.       steer_gain = STEER_GAIN[0];
  229.       vc_nex = VC[0];
  230.       dist_val_after = s.nex_len;
  231.       turn_size = 1.0;
  232.        }
  233.        else if (s.nex_rad > 0.0)
  234.        {
  235.       float ln_rad = log(s.nex_rad);
  236.       int low = (int)ln_rad;
  237.       int high = low+1;
  238.       float low_wt = high - ln_rad;
  239.       float high_wt = ln_rad - low;
  240.  
  241.       if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
  242.       if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
  243.       lane_ratio = (low_wt*LANE_RATIO[low] + high_wt*LANE_RATIO[high])
  244. - lft_ratio;
  245.       steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
  246.       vc_nex = (low_wt*VC[low] + high_wt*VC[high]);
  247.       dist_val_after = s.nex_len * s.nex_rad;
  248.       turn_size = (fabs(s.nex_rad) -
  249. fabs(cos(s.nex_len)*s.nex_rad))/(.75*width);
  250.       // adjust calculated size in case turn > 90 degrees
  251.       if (fabs(s.nex_len) > 1.5) turn_size = 1.0;
  252.        }
  253.        else if (s.nex_rad < 0.0)
  254.        {
  255.       float ln_rad = log(-s.nex_rad);
  256.       int low = (int)ln_rad;
  257.       int high = low+1;
  258.       float low_wt = high - ln_rad;
  259.       float high_wt = ln_rad - low;
  260.  
  261.       if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
  262.       if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
  263.       lane_ratio = rgt_ratio - (low_wt*LANE_RATIO[low] +
  264. high_wt*LANE_RATIO[high]);
  265.       steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
  266.       vc_nex = (low_wt*VC[low] + high_wt*VC[high]);
  267.       dist_val_after = -s.nex_len * s.nex_rad;
  268.       turn_size = (fabs(s.nex_rad) -
  269. fabs(cos(s.nex_len)*s.nex_rad))/(.75*width);
  270.       // adjust calculated size in case turn > 90 degrees
  271.       if (fabs(s.nex_len) > 1.5) turn_size = 1.0;
  272.        }
  273.        alpha_nex = steer_gain * lane_ratio;
  274.    }
  275.    // calculate vc for second turn ahead
  276.    {
  277.        if (s.after_rad == 0.0)
  278.        {
  279.       vc_after = VC[0];
  280.        }
  281.        else if (s.after_rad > 0.0)
  282.        {
  283.       float ln_rad = log(s.after_rad);
  284.       int low = (int)ln_rad;
  285.       int high = low+1;
  286.       float low_wt = high - ln_rad;
  287.       float high_wt = ln_rad - low;
  288.  
  289.       if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
  290.       if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
  291.       vc_after = (low_wt*VC[low] + high_wt*VC[high]);
  292.        if (s.nex_rad == 0.0)
  293.        {
  294.           float lane_ratio, steer_gain;
  295.           lane_ratio = (low_wt*LANE_RATIO[low] +
  296. high_wt*LANE_RATIO[high]) - lft_ratio;
  297.           steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
  298.           alpha_nex = steer_gain * lane_ratio;
  299.        }
  300.        }
  301.        else if (s.after_rad < 0.0)
  302.        {
  303.       float ln_rad = log(-s.after_rad);
  304.       int low = (int)ln_rad;
  305.       int high = low+1;
  306.       float low_wt = high - ln_rad;
  307.       float high_wt = ln_rad - low;
  308.  
  309.       if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
  310.       if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
  311.       vc_after = (low_wt*VC[low] + high_wt*VC[high]);
  312.        if (s.nex_rad == 0.0)
  313.        {
  314.           float lane_ratio, steer_gain;
  315.           lane_ratio = rgt_ratio - (low_wt*LANE_RATIO[low] +
  316. high_wt*LANE_RATIO[high]);
  317.           steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
  318.           alpha_nex = steer_gain * lane_ratio;
  319.        }
  320.        }
  321.    }
  322.  
  323.    // Blend values for current and next based on speed/distance ratio
  324.    // vc is calculated without regard for power requirements or loss of traction;
  325.    // this should probably change in the future
  326.    // look ahead to second turn; if too far to care, then look at next turn.
  327.    // second lookahead only for speed adjustment, not for turning (so far)
  328.    // also adjust dval for nearest turn -- some turns are too short and
  329.    // too shallow to require much adjustment to speed. (keep alpha normal)
  330.  
  331.    if (turn_size > 1.0) turn_size = 1.0;
  332.    if (s.v < 0.001) dval = 1.0;
  333.    else dval = (dist_parm * (dist_val + dist_val_after)/s.v);
  334.    if ((dval >= 1.0) || (vc_nex < vc_after))
  335.    {
  336.       if (s.v < 0.001) dval = 1.0;
  337.       else dval = (dist_parm * dist_val/s.v);
  338.    }
  339.    else
  340.    {
  341.       vc_nex = vc_after;
  342.    }
  343.    dval = dval*dval;  // attempt to correct offtrack at end of high-speed sections
  344.    if (dval < 0.0) dval = 0.0;
  345.    if (dval > 1.0) dval = 1.0;
  346.    alpha = (dval * alpha_cur + (1 - dval) * alpha_nex)
  347.      - damp_gain * s.vn/s.v + s.v*s.v*bias;
  348.    dval = dval/turn_size;  // scale importance of next turn by size
  349.    if (dval < 0.0) dval = 0.0;
  350.    if (dval > 1.0) dval = 1.0;
  351.    vc = dval * vc_cur + (1 - dval) * vc_nex;
  352.  
  353.    // these are nominal values based on track following.  now need to look
  354.    // at other cars to see if there's a collision risk and modify the values
  355.    // accordingly.
  356.  
  357.    coll_cnt = 0;
  358.    coll_alpha = 0;
  359.    coll_vc = vc;
  360.    for (i=0;i<3;i++)
  361.    {
  362.        if (s.nearby[i].who > 16) continue;
  363.        if (s.nearby[i].rel_y < 0.0) continue;  // don't worry about those behind
  364.        collrisk_x[i] = 0; // no collision risk with this vehicle
  365.        collrisk_y[i] = 0;
  366.  
  367.        if (((s.nearby[i].rel_x > 0 && s.nearby[i].rel_xdot < 0) ||
  368.         (s.nearby[i].rel_x < 0 && s.nearby[i].rel_xdot > 0)) &&
  369.         (fabs(s.nearby[i].rel_xdot) > 0.01))
  370.        {
  371.       // vehicles are closing the x distance
  372.        collrisk_x[i] = 1;
  373.        }
  374.        if (((s.nearby[i].rel_y > 0 && s.nearby[i].rel_ydot < 0) ||
  375.         (s.nearby[i].rel_y < 0 && s.nearby[i].rel_ydot > 0)) &&
  376.         (fabs(s.nearby[i].rel_ydot) > 0.01))
  377.        {
  378.       // vehicles are closing the y distance
  379.        collrisk_y[i] = 1;
  380.        }
  381.     // if no convergence, then no chance of collision
  382.        if (collrisk_x[i] == 0 && collrisk_y[i] == 0) continue;
  383.     // there's some chance of collision with this vehicle
  384.     // try to calculate better odds and timing
  385.     // look at x-axis first
  386.     if (collrisk_x[i])
  387.     {
  388.         colltime =
  389. (fabs(s.nearby[i].rel_x)-CARWID)/fabs(s.nearby[i].rel_xdot);
  390.         if (colltime < 2.0)  // less than 2 seconds to react
  391.         {
  392.         // what will the rely be at colltime?
  393.         pred_rely = s.nearby[i].rel_y + s.nearby[i].rel_ydot * colltime;
  394.         if (fabs(pred_rely) < CARLEN)  // within a carlength?
  395.         {
  396.             coll_cnt++;
  397.             if (s.cur_rad == 0) // straightaway
  398.             {
  399.                 if (s.nex_rad > 0.0)
  400.                 {
  401.                   if (lft_ratio < LEFT_TOO_CLOSE)
  402.                   {
  403.                   coll_vc = 0.95 * s.v;
  404.                   coll_alpha += 0.0;
  405.                   }
  406.                   else
  407.                   {
  408.                 if (s.nearby[i].rel_x > 0.0)
  409.                 {coll_vc = 0.95 * s.v;}
  410.                   coll_alpha += (3.141592/18.0);
  411.                   }
  412.                 }
  413.                 else
  414.                 {
  415.                   if (lft_ratio > RIGHT_TOO_CLOSE)
  416.                   {
  417.                   coll_vc = 0.95 * s.v;
  418.                   coll_alpha += 0.0;
  419.                   }
  420.                   else
  421.                   {
  422.                 if (s.nearby[i].rel_x < 0.0)
  423.                 {coll_vc = 0.95 * s.v;}
  424.                   coll_alpha -= (3.141592/18.0);
  425.                   }                     }
  426.             }
  427.             else if (s.cur_rad > 0.0)  // left turn
  428.             {
  429.                 if (s.nearby[i].rel_x < 0.0)
  430.                 {
  431.                   coll_vc = 0.95 * s.v;
  432.                   coll_alpha -= (3.141592/18.0);
  433.                 }
  434.                 else
  435.                 {coll_alpha += (3.141592/18.0);}
  436.             }
  437.             else  // (s.cur_rad < 0.0)  // right turn
  438.             {
  439.                 if (s.nearby[i].rel_x > 0.0)
  440.                 {
  441.                   coll_vc = 0.95 * s.v;
  442.                   coll_alpha += (3.141592/18.0);
  443.                 }
  444.                 else
  445.                 {coll_alpha -= (3.141592/18.0);}
  446.             }
  447.         }
  448.         }
  449.     }
  450.     if (collrisk_y[i])
  451.     {
  452.         colltime =
  453. (fabs(s.nearby[i].rel_y)-CARLEN)/fabs(s.nearby[i].rel_ydot);
  454.         if (colltime < 2.0)  // less than 2 seconds to react
  455.         {
  456.         // what will the relx be at colltime?
  457.         pred_relx = s.nearby[i].rel_x + s.nearby[i].rel_xdot * colltime;
  458.         if (fabs(pred_relx) < CARWID)  // within a carwidth?
  459.         {
  460.             coll_cnt++;
  461.             if (s.cur_rad == 0) // straightaway
  462.             {
  463.                 if (s.nex_rad > 0.0)
  464.                 {
  465.                   if (lft_ratio < LEFT_TOO_CLOSE)
  466.                   {
  467.                   coll_vc = 0.95 * s.v;
  468.                   coll_alpha += 0.0;
  469.                   }
  470.                   else
  471.                   {
  472.                 if (s.nearby[i].rel_x > 0.0)
  473.                 {coll_vc = 0.95 * s.v;}
  474.                   coll_alpha += (3.141592/18.0);
  475.                   }
  476.                 }
  477.                 else
  478.                 {
  479.                   if (lft_ratio > RIGHT_TOO_CLOSE)
  480.                   {
  481.                   coll_vc = 0.95 * s.v;
  482.                   coll_alpha += 0.0;
  483.                   }
  484.                   else
  485.                   {
  486.                 if (s.nearby[i].rel_x < 0.0)
  487.                 {coll_vc = 0.95 * s.v;}
  488.                   coll_alpha -= (3.141592/18.0);
  489.                   }                     }
  490.             }
  491.             else if (s.cur_rad > 0.0)  // left turn
  492.             {
  493.                 if (s.nearby[i].rel_x <= 0.0)
  494.                 {
  495.                   coll_vc = 0.95 * s.v;
  496.                   coll_alpha -= (3.141592/18.0);
  497.                 }
  498.                 else
  499.                 {coll_alpha += (3.141592/18.0);}
  500.             }
  501.             else  // (s.cur_rad < 0.0)  // right turn
  502.             {
  503.                 if (s.nearby[i].rel_x > 0.0)
  504.                 {
  505.                   coll_vc = 0.95 * s.v;
  506.                   coll_alpha += (3.141592/18.0);
  507.                 }
  508.                 else
  509.                 {coll_alpha -= (3.141592/18.0);}
  510.             }
  511.         }
  512.         }
  513.     }
  514.    }
  515.    if (coll_cnt > 0)
  516.    {
  517.     coll_alpha /= (double)coll_cnt;
  518.    }
  519.    result.vc = coll_vc;   result.alpha = alpha+coll_alpha;
  520.    return result;
  521. }
  522.  
  523.  
  524.  
  525.